#!/usr/bin/env node

const Koa = require('koa')
const send = require('koa-send')
const path = require('path')
const compiler = require('@vue/compiler-sfc')
const {Readable} = require('stream')

const app = new Koa()

const stream2String = stream => new Promise((resolve, reject) => {
    const chunks = []
    stream.on('data', chunk => chunks.push(chunk))
    stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')))
    stream.on('error', reject)
})
const string2Stream = text => {
    const stream = new Readable()
    stream.push(text)
    stream.push(null) // 标识写完了
    return stream
}


//  3.处理静态资源之前处理 /@modules
app.use(async (ctx, next) => {
    if (ctx.path.startsWith('/@modules/')) {
        const moduleName = ctx.path.substr(10)
        const pkgPath = path.join(process.cwd(),'node_modules',moduleName,'package.json') 
        const pkg = require(pkgPath)
        ctx.path = path.join('/node_modules',moduleName,pkg.module)
    }
    await next()
})

// 1. 开启静态文件服务器
app.use(async (ctx, next) => {
    await send(ctx, ctx.path, { root: process.cwd(), index: 'index.html' })
    await next()
})

// 5. 简单处理 css
app.use(async (ctx,next)=>{
    if(ctx.path.endsWith('.css')){
        let contents = await stream2String(ctx.body)
        let code = `
        let css = "${contents.replace(/\n/g," ")}"
        const sheet = new CSSStyleSheet()
        sheet.replaceSync(css);
        document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]
        export default css
        `
        ctx.type = 'application/javascript'
        ctx.body = string2Stream(code)  
    }
    await next()
})

// 4.浏览器只能处理 js 模块，无法处理单文件组件、import css，需要编译
app.use(async(ctx,next)=>{
    if(ctx.path.endsWith('.vue')){
        const contents = await stream2String(ctx.body)
        const {descriptor} = compiler.parse(contents)
        let code
        if(!ctx.query.type){
            code = descriptor.script.content.replace(/export\s+default\s+/g,'const __script=')
            code += `
            import {render as __render} from "${ctx.path}?type=template"
            __script.render = __render
            export default __script`
        }else if(ctx.query.type === 'template'){
            const templateRender = compiler.compileTemplate({source:descriptor.template.content})
            code = templateRender.code
        }
        ctx.type = 'application/javascript'
        ctx.body = string2Stream(code)
    }
    await next()
})
//  2.修改第三方模块路径
app.use(async (ctx, next) => {
    if (ctx.type === 'application/javascript') {
        const contents = await stream2String(ctx.body)
        ctx.body = contents
        .replace(/(from\s+['"])(?![\.\/])/g,'$1/@modules/')
        .replace(/process\.env\.NODE_ENV/g,"'development'")
    }
    await next()
})

app.listen(3000, () => {
    console.log(`server running @ http://localhost:3000`)
})

